﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NAccounting.Models;
using AutoMapper;
using System.Threading;
using System.Web.Routing;
using NAccounting.QueryObjects;

namespace NAccounting.Controllers
{
    public class AccountEntryController : Controller
    {
        private NAccountEntities db = new NAccountEntities();

        //
        // GET: /AccountEntry/

        public ActionResult Index()
        {
            var model = new AccountEntryListModel();
            return View(model);
        }

        //
        // GET: /AccountEntry/Details/5

        public ActionResult Details(int id = 0)
        {
            Lot lot = db.Lots.Single(l => l.Id == id);
            if (lot == null)
            {
                return HttpNotFound();
            }
            return View(lot);
        }

        //
        // GET: /AccountEntry/Edit/5

        public ActionResult Create()
        {
            if (Request.QueryString["Lot"] == null) return HttpNotFound("Lot nout found");

            var id = 0;

            if (!Int32.TryParse(Request.QueryString["Lot"], out id))
                return HttpNotFound("Invalid lot number");

            var lot = db.Lots.SingleOrDefault(x => x.Id == id);
            var model = CreateNewAccountEntryDetailModel(lot);

            return View("Edit", model);
        }


        public ActionResult Edit(int id = 0)
        {
            var entity = db.AccountEntries.SingleOrDefault(x => x.Id == id);
            if (entity == null) return HttpNotFound("Lançamento não encontrado");

            var model = Mapper.Map<AccountEntry, AccountEntryDetailModel>(entity);
            return View(model);
        }

        [HttpPost]
        public ActionResult Edit(AccountEntryDetailModel model)
        {
            return Create(model);
        }

        [HttpPost]
        public ActionResult Create(AccountEntryDetailModel model)
        {
            if (ModelState.IsValid)
            {
                var entity = db.AccountEntries.SingleOrDefault(x => x.Id == model.AccountEntryId);

                if (entity == null)
                    entity = db.AccountEntries.CreateObject();

                Mapper.Map<AccountEntryDetailModel, AccountEntry>(model, entity);
                var saveMode = (AccountEntrySaveMode)model.SaveMode;

                var lot = db.Lots.SingleOrDefault(x => x.Id == model.LotId);
                lot.Open();

                if (!lot.AccountEntries.Any(x => x.Id == entity.Id))
                {
                    lot.Add(entity);
                }
                else
                {
                    lot.Balance();
                }

                ActionResult result = null;

                if (saveMode == AccountEntrySaveMode.SaveAndCloseLot)
                {
                    try
                    {
                        lot.Close();
                        //TODO: Change redirect
                        result = RedirectToAction("Index", "Lot");
                    }
                    catch (Exception ex)
                    {
                        var errorInfo = new HandleErrorInfo(ex, "AccountEntry", "Save");
                        return View("Error", errorInfo);
                    }
                }
                else if (saveMode == AccountEntrySaveMode.SaveAndNew)
                {
                    result = RedirectToAction("Create", new RouteValueDictionary(new { controller = "accountEntry", action = "Create", Id = model.LotId }));
                }
                else
                {
                    result = RedirectToAction("Index");
                }

                db.SaveChanges();
                return result;
            }

            return View("Edit", model);
        }

        public ActionResult GetAccountEntryByFilter(string sidx, string sord, int page, int rows)
        {
            var queryObject = new AccountEntryQueryObject(db);
            var dateOption = Request.QueryString["DateOption"];

            if (!String.IsNullOrEmpty(dateOption))
            {
                var period = FilterDateOptions.GetPeriodByDateOption(dateOption);
                queryObject.Period = period;
            }

            var pageIndex = page - 1;
            var pagedResult = queryObject.Get(pageIndex, rows);

            var totalRecords = pagedResult.Total;
            var totalPages = (int)Math.Ceiling((float)totalRecords / (float)rows);

            var jsonResult = new
            {
                totalPages = totalPages,
                page = page,
                records = totalRecords,
                rows = (
                    from e in pagedResult.List
                    let cellValues = new
                    {
                        Id = e.Id.ToString(),
                        Actions = "",
                        Description = e.Description,
                        Lot = e.Lot.Description,
                        LotId = e.LotId,
                        AccountPlan = e.AccountPlan.ToString(),
                        Type = e.Type == "C" ? "Crédito" : "Débito",
                        Date = e.Date,
                        Value = e.Value,
                        canEdit = Boolean.TrueString.ToLower()
                    }
                    select new
                    {
                        id = e.Id,
                        cell = new string[]{
                             cellValues.Id, 
                             cellValues.Actions, 
                             cellValues.Description, 
                             cellValues.Lot,
                             cellValues.LotId.ToString(),
                             cellValues.AccountPlan,
                             cellValues.Type,
                             cellValues.Date.ToString(System.Threading.Thread.CurrentThread.CurrentUICulture.DateTimeFormat.ShortDatePattern),
                             String.Format("{0} {1}", System.Threading.Thread.CurrentThread.CurrentUICulture.NumberFormat.CurrencySymbol, cellValues.Value.ToString()),
                             cellValues.canEdit
                        }
                    }).ToArray()
            };

            return Json(jsonResult, JsonRequestBehavior.AllowGet);
        }

        public ActionResult GetByLot(string sidx, string sord, int page, int rows)
        {
            var lot = Request.QueryString["LotId"];

            var lotId = lot != null && lot != "" ? int.Parse(lot) : 0;
            var queryObject = new AccountEntryQueryObject(db) { LotId = lotId };


            var pageIndex = page - 1;
            var pagedResult = queryObject.Get(pageIndex, rows);
            var totalPages = (int)Math.Ceiling((float)pagedResult.Total / (float)rows);

            var jsonResult = new
            {
                totalPages = totalPages,
                page = page,
                records = pagedResult.Total,
                rows = (
                    from e in pagedResult.List
                    let cellValues = new
                    {
                        Id = e.Id.ToString(),
                        Actions = "",
                        Description = e.Description,
                        Lot = e.Lot.Description,
                        LotId = e.LotId,
                        AccountPlan = e.AccountPlan.ToString(),
                        Type = e.Type == "C" ? "Crédito" : "Débito",
                        Date = e.Date,
                        Value = e.Value,
                        canEdit = Boolean.TrueString.ToLower()
                    }
                    select new
                    {
                        id = e.Id,
                        cell = new string[]{
                             cellValues.Id, 
                             cellValues.Actions, 
                             cellValues.Description, 
                             cellValues.AccountPlan,
                             cellValues.Type,
                             cellValues.Date.ToString(System.Threading.Thread.CurrentThread.CurrentUICulture.DateTimeFormat.ShortDatePattern),
                             cellValues.Value.ToCurrencyString(),
                             cellValues.canEdit
                        }
                    }).ToArray()
            };

            return Json(jsonResult, JsonRequestBehavior.AllowGet);
        }

        //
        // GET: /AccountEntry/Delete/5

        public ActionResult Delete(int id = 0)
        {
            var entity = db.AccountEntries.SingleOrDefault(x => x.Id == id);
            if (entity == null) return HttpNotFound();

            if (!entity.CanDelete)
            {
                var errorInfo = new HandleErrorInfo(new InvalidOperationException("Não foi possível excluir o lançmento <br /> O lote já encontra-se fechado."), "AccountEntry", "Delete");
                return View("Error", errorInfo);
            }

            entity.Lot.Remove(entity);

            db.AccountEntries.DeleteObject(entity);
            db.SaveChanges();

            return RedirectToAction("Index");
        }

        private static AccountEntryDetailModel CreateNewAccountEntryDetailModel(Lot lot)
        {
            var culture = Thread.CurrentThread.CurrentUICulture;
            var totalCredit = lot.TotalCredit.HasValue ? lot.TotalCredit.Value : 0;
            var totalDebit = lot.TotalDebit.HasValue ? lot.TotalDebit.Value : 0;
            var model = new AccountEntryDetailModel
            {
                LotId = lot.Id,
                LotDescription = lot.Description,
                LotPeriod = String.Format("{0} até {1}", lot.StartPeriod.ToString(culture.DateTimeFormat.ShortDatePattern),
                                                         lot.EndPeriod.ToString(culture.DateTimeFormat.ShortDatePattern)),
                LotTotalCredit = String.Format("{0} {1}", culture.NumberFormat.CurrencySymbol, totalCredit.ToString()),
                LotTotalDebit = String.Format("{0} {1}", culture.NumberFormat.CurrencySymbol, totalDebit.ToString()),
                MinDateJs = lot.StartPeriod.ToJsString(),
                MaxDateJs = lot.EndPeriod.ToJsString(),
                LotIsValidJs = lot.MayReceiveRelease.ToString().ToLower(),
                CanDelete = Boolean.FalseString.ToLower()
            };

            return model;
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}